Passed
Push — master ( f9e2c0...85325c )
by Rafael S.
01:25
created

read-write.js ➔ readBytes   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
c 1
b 0
f 0
nc 4
nop 2
dl 0
loc 15
rs 9.4285
1
/**
2
 * from-bytes: Numbers and strings from bytes.
3
 * Copyright (c) 2017 Rafael da Silva Rocha.
4
 * https://github.com/rochars/byte-data
5
 */
6
7
const Type = require("../src/type");
8
const endianness = require("endianness");
9
10
/**
11
 * Turn a byte buffer into what the bytes represent.
12
 * @param {!Array<number>|!Array<string>|Uint8Array} buffer An array of bytes.
13
 * @param {Object} type One of the available types.
14
 * @return {!Array<number>|number|string}
15
 */
16
function fromBytes(buffer, type) {
17
    makeBigEndian(buffer, type);
18
    bytesFromBase(buffer, type.base);
19
    let values = readBytes(
20
            buffer,
21
            type
22
        );
23
    if (type.single) {
24
        values = getSingleValue(values, type);
25
    }
26
    return values;
27
}
28
29
/**
30
 * Turn numbers and strings to bytes.
31
 * @param {!Array<number>|number|string} values The data.
32
 * @param {Object} type One of the available types.
33
 * @return {!Array<number>|!Array<string>|Uint8Array} the data as a byte buffer.
34
 */
35
function toBytes(values, type) {
36
    let bytes = writeBytes(values, type);
37
    makeBigEndian(bytes, type);
38
    if (type.base != 10) {
39
        bytesToBase(bytes, type.base);
40
        formatOutput(bytes, type);
41
    }
42
    return bytes;
43
}
44
45
/**
46
 * Get the full type spec for the reading/writing.
47
 * @param {Object} atype One of the available types.
48
 * @param {number} base The base of the input.
49
 * @param {boolean} single True if its a single value, false for array.
50
 * @return {Object}
51
 */
52
function getType(atype, base, single) {
53
    let theType = Object.assign(new Type({}), atype);
54
    theType.base = base;
55
    theType.single = single;
56
    return theType;
57
}
58
59
/**
60
 * Make a single value an array in case it is not.
61
 * If the value is a string it stays a string.
62
 * @param {!Array<number>|number|string} values The value or values.
63
 * @return {!Array<number>|string}
64
 */
65
function turnToArray(values) {
66
    if (!Array.isArray(values) && typeof values != "string") {
67
        values = [values];
68
    }
69
    return values;
70
}
71
72
/**
73
 * Return the first value from the result value array.
74
 * @param {!Array<number>|string} values The values.
75
 * @param {Object} type One of the available types.
76
 * @return {number|string}
77
 */
78
function getSingleValue(values, type) {
79
    if (type.char) {
80
        values = values.slice(0, type.bits / 8);
81
    } else {
82
        values = values[0];
83
    }
84
    return values;
85
}
86
87
/**
88
 * Turn a array of bytes into an array of what the bytes should represent.
89
 * @param {!Array<number>|Uint8Array} bytes An array of bytes.
90
 * @param {Object} type The type.
91
 * @return {!Array<number>|string}
92
 */
93
function readBytes(bytes, type) {
94
    let values = [];
95
    let i = 0;
96
    let len = bytes.length - (type.offset - 1);
97
    while (i < len) {
98
        values.push(
99
                type.sign(type.reader(bytes, i, type))
100
            );
101
        i += type.offset;
102
    }
103
    if (type.char) {
104
        values = values.join("");
105
    }
106
    return values;
107
}
108
109
/**
110
 * Turn bytes to base 10.
111
 * @param {!Array<number>|Uint8Array} bytes The bytes as binary or hex strings.
112
 * @param {number} base The base.
113
 */
114
function bytesFromBase(bytes, base) {
115
    if (base != 10) {
116
        let i = 0;
117
        let len = bytes.length;
118
        while(i < len) {
119
            bytes[i] = parseInt(bytes[i], base);
120
            i++;
121
        }
122
    }
123
}
124
125
/**
126
 * Swap the endianness to big endian.
127
 * @param {!Array<number>|!Array<string>|Uint8Array} bytes The values.
128
 * @param {Object} type The type.
129
 */
130
function makeBigEndian(bytes, type) {
131
    if (type.be) {
132
        endianness(bytes, type.offset);
133
    }
134
}
135
136
/**
137
 * Turn the output to the correct base.
138
 * @param {Array} bytes The bytes.
139
 * @param {Object} type The type.
140
 */
141
function formatOutput(bytes, type) {
142
    if (type.bits > 1) {
143
        let i = 0;
144
        let len = bytes.length;
145
        let offset = getOutputByteOffset(type);
146
        while(i < len) {
147
            bytes[i] = Array(offset - bytes[i].length).join("0") + bytes[i];
148
            i++;
149
        }
150
    }
151
}
152
153
/**
154
 * Get the number of chars a non-string output should have
155
 * according to the number of bits used by the type.
156
 * @param {Object} type The type.
157
 * @return {number}
158
 */
159
function getOutputByteOffset(type) {
160
    let offset = 1;
161
    if (type.bits == 2) {
162
        offset = (type.base == 2 ? 2 : 2) + 1;
163
    } else  if (type.bits == 4) {
164
        offset = (type.base == 2 ? 4 : 1) + 1;
165
    } else if (type.bits >= 4) {
166
        offset = (type.base == 2 ? 8 : 2) + 1;
167
    }
168
    return offset;
169
}
170
171
/**
172
 * Turn bytes to base 2, 10 or 16.
173
 * @param {!Array<string>|!Array<number>|null} bytes The bytes.
174
 * @param {number} base The base.
175
 */
176
function bytesToBase(bytes, base) {
177
    let i = 0;
178
    let len = bytes.length;
179
    while (i < len) {
180
        bytes[i] = bytes[i].toString(base);
181
        i++;
182
    }
183
}
184
185
/**
186
 * Write values as bytes.
187
 * @param {!Array<number>|number|string} values The data.
188
 * @param {Object} type One of the available types.
189
 * @return {!Array<number>} the bytes.
190
 */
191
function writeBytes(values, type) {
192
    let i = 0;
193
    let j = 0;
194
    let len = values.length;
195
    let bytes = [];
196
    while (i < len) {
197
        j = type.writer(bytes, type.overflow(values[i]), j);
198
        i++;
199
    }
200
    return bytes;
201
}
202
203
module.exports.getType = getType;
204
module.exports.turnToArray = turnToArray;
205
module.exports.toBytes = toBytes;
206
module.exports.fromBytes = fromBytes;
207